﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO.Ports;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using NovoDataBase;
using NovoFileIO;
using NovoUSB2XXX;
using NovoSerDes;
using NovoUI.UserCtrl;
using System.Diagnostics;
using System.Windows.Forms.VisualStyles;
using System.Threading;
using NovoSerDes.Forms;

namespace NovoUI
{
    [Serializable]
    public partial class FormMain : Form
    {
        #region Variable Define
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

        DataSet DS_Excel;
        Novo_Excel excel_Op = new Novo_Excel();
        NovoDataSet DataSet;
        RegisterMap regMap;
        List<MDRegisterViewTab> AllTables = new List<MDRegisterViewTab> { };

        SerDesComm myUsbDev = null;// = new SerDesComm(0);
        int maxUSBDevCount = 5;
        List<String> historyProjPath = new List<string> { };
        int maxHistProjPathCount = 10;
        String currentProjPath = "";
        #endregion Define

        #region Funcs
        public FormMain()
        {
            InitializeComponent();

            myUsbDev = new SerDesComm();
            Process currentProc = Process.GetCurrentProcess();
            Process[] tempPorcList = Process.GetProcessesByName(currentProc.ProcessName);
            //maxUSBDevCount = tempPorcList.Length;
            if (tempPorcList.Length >= 2)
            {
                string devName = myUsbDev.GetDevName();
                setIICDevice = new Form_SetIICDevice(myUsbDev.DevID, maxUSBDevCount, devName, myUsbDev.CurrentDevAddr,
                    myUsbDev.I2C_CFG.ClockSpeedHz, myUsbDev.I2C_CFG.EnablePu);
                setIICDevice.FormClosingEvent += new Form_SetIICDevice.SetIICDevClosingEventHandler(SetIICDevClosingEvent);
                setIICDevice.ShowDialog();
            }
            else
            {
                myUsbDev.OpenDevice(0);
            }
            RefreshDongleInfo();
            //int tempCnt = myUsbDev.EnumDevice();


            CreateCommonTabs();

            toolStripMenuChipType_Click(this.toolStrip_NLS9116, null);
        }

        private string GenerateVersion()
        {
            string _ver = "NovoSense-SerDes Eva v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();

            return _ver;
        }

        private void RefreshDongleInfo()
        {
            this.statusBar_DeviceConnected.Text =  myUsbDev.IsOpen ?  "Connected" : "Disconnected";
            this.statusBar_DeviceConnected.BackColor = myUsbDev.IsOpen ? Color.Green : Color.IndianRed;

            this.statusBar_DeviceName.Text = myUsbDev.IsOpen ? 
                String.Format("{0} - {1}", myUsbDev.GetDevName(), myUsbDev.DevID) : "No Device";
            if(myUsbDev.IsOpen) 
            {
                FlashLED();
                //// DSR0 - GPIO2, DTR0 - GPIO5, LED ON when GPIO is set to zero 
                //byte mask = 1 << 2 | 1 << 5;
                //byte data = (byte)((myUsbDev.DevID == 1) ? 0 : (1 << 2));
                //myUsbDev.GPIO_Set(mask, data);
            }
        }

        private void FlashLED()
        {
            // DSR0 - GPIO2, DTR0 - GPIO5, LED ON when GPIO is set to zero
            byte mask = 1 << 2;    //1 << 2 | 1 << 5;
            int flashCount = 3;
            
            if (myUsbDev.IsOpen)
            {
                while (flashCount-- > 0)
                {
                    myUsbDev.GPIO_Set(mask, mask);  //LED OFF
                    Thread.Sleep(500);
                    myUsbDev.GPIO_Set(mask, 0);     // LED ON
                    Thread.Sleep(500);
                    //myUsbDev.GPIO_Set(mask, mask);  // LED OFF
                }
            }
        }

        private DataSet ImportExcel(string excelFileName)
        {
            try
            {
                DataTable dtExcel = new DataTable();
                //数据表
                DataSet ds = new DataSet();
                //获取文件扩展名
                string strExtension = System.IO.Path.GetExtension(excelFileName);
                string strFileName = System.IO.Path.GetFileName(excelFileName);
                //Excel的连接
                OleDbConnection objConn = null;
                switch (strExtension)
                {
                    case ".xls":
                        objConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
                            excelFileName + ";" + "Extended Properties=\"Excel 8.0;HDR=NO;IMEX=1;\"");
                        break;
                    case ".xlsx":
                        objConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" +
                            excelFileName + ";" + "Extended Properties=\"Excel 12.0;HDR=NO;IMEX=1;\"");
                        break;
                    default:
                        objConn = null;
                        break;
                }

                if (objConn == null)
                {
                    return null;
                }
                objConn.Open();

                // Get all sheet name in the excel                
                ArrayList result = new ArrayList { };
                DataTable sheetNames = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,
                    new object[] { null, null, null, "TABLE" });
                foreach (DataRow dr in sheetNames.Rows)
                {
                    result.Add(dr[2]);
                }

                // Get all datatable from each sheet and add to ds.
                ds.Clear();
                string strSql;
                foreach (string tName in result)
                {
                    strSql = "select * from [" + tName + "]";
                    OleDbCommand objCmd = new OleDbCommand(strSql, objConn);
                    OleDbDataAdapter myData = new OleDbDataAdapter(strSql, objConn);
                    myData.Fill(ds, tName);//填充数据
                }
                objConn.Close();

                return ds;
            }
            catch { return null; }
        }

        private void CreateTabs(DataSet _ds)
        {

            this.tabCtrlRegView.TabPages.Clear();
            AllTables.Clear();

            int ix_page = 0;
            for (int ix_tab = 0; ix_tab < _ds.Tables.Count; ix_tab++)
            {
                if ((_ds.Tables[ix_tab].Rows.Count == 0) && (_ds.Tables[ix_tab].TableName != "Customer"))
                    continue;

                this.tabCtrlRegView.TabPages.Add(_ds.Tables[ix_tab].TableName);
                MDRegisterViewTab newTab = new MDRegisterViewTab(_ds.Tables[ix_tab], _ds.Tables["Customer"], DataSet.RegMap, myUsbDev);
                this.tabCtrlRegView.TabPages[ix_page++].Controls.Add(newTab);
                AllTables.Add(newTab);
                newTab.Dock = DockStyle.Fill;
                newTab.BorderStyle = BorderStyle.Fixed3D;
            }
            CreateCommonTabs();
            //this.Refresh();
        }


        TabControl scriptTC = new TabControl();
        FormScript frm_script;
        private void CreateCommonTabs()
        {
            if (tabCtrlRegView.TabPages.ContainsKey("Script"))
                return;

            //Create script tab
            this.tabCtrlRegView.TabPages.Add("Script");
            bool ifMultiScriptWin = true; 

            if (ifMultiScriptWin)
            {
                scriptTC.Alignment = TabAlignment.Right;
                this.tabCtrlRegView.TabPages[tabCtrlRegView.TabPages.Count - 1].Controls.Add(scriptTC);
                scriptTC.Dock = DockStyle.Fill;
                if (scriptTC.TabPages.Count == 0)
                {
                    int maxScriptWinCnt = 5;
                    
                    //scriptTC.Appearance = TabAppearance.FlatButtons;
                    //scriptTC.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
                    for (int ix = 0; ix < maxScriptWinCnt; ix++)
                    {
                        FormScript frm_script = new FormScript(myUsbDev);
                        scriptTC.TabPages.Add("Script" + ix.ToString());
                        scriptTC.TabPages[ix].Controls.Add(frm_script);
                        frm_script.Dock = DockStyle.Fill;
                        frm_script.BorderStyle = BorderStyle.Fixed3D;
                    }
                    //scriptTC.Alignment = TabAlignment.Bottom;
                }
            }
            else
            {
                frm_script = new FormScript(myUsbDev);
                this.tabCtrlRegView.TabPages[tabCtrlRegView.TabPages.Count - 1].Controls.Add(frm_script);
                frm_script.Dock = DockStyle.Fill;
                frm_script.BorderStyle = BorderStyle.Fixed3D;
            }

            //TabControl scriptTC = new TabControl();
            //scriptTC.Dock = DockStyle.Fill;
            //scriptTC.Appearance = TabAppearance.FlatButtons;
            //scriptTC.Alignment = TabAlignment.Right;
            ////scriptTC.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
            //scriptTC.TabPages.Add("Script1");
            //scriptTC.TabPages[scriptTC.TabPages.Count - 1].Controls.Add(frm_script);
            //this.tabCtrlRegView.TabPages[tabCtrlRegView.TabPages.Count - 1].Controls.Add(scriptTC);


            //frm_script.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
        }

        private void SerializeMethod(string path)
        {
            //创建一个格式化程序的实例
            IFormatter formatter = new BinaryFormatter();             //创建一个文件流
            Stream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
            formatter.Serialize(stream, DataSet);
            stream.Close();
        }

        private void DeserializeMethod(string path)
        {
            //创建一个文件流
            IFormatter formatter = new BinaryFormatter();
            Stream destream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);              
            DataSet = formatter.Deserialize(destream) as NovoDataSet;
            destream.Close();

            //To DO: Add create taps on GUI with dataset
        }
        #endregion Funcs

        #region Events
        #region Auto Dongle Detect
        public const int WM_DEVICECHANGE = 537;
        private const int WM_CH347DevArrive = 0x0010;
        private const int WM_CH347DevRemove = 0x0011;

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m); 

            if(m.Msg == WM_DEVICECHANGE)
            {
                myUsbDev.ReOpenDevice();
                RefreshDongleInfo();
                //Console.WriteLine("m.WParam = {0}, {1}", m.WParam.ToInt32(), m.ToString());
            }
        }
        #endregion 

        private void FormMain_Load(object sender, EventArgs e)
        {
            this.Text = GenerateVersion();
        }
        private void MenuItemFile_Open_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Please select regmap excel file...";
            ofd.Filter = "xlsx(*.xlsx)|*.xlsx|xls(*.xls)|*.xls|All Files(*.*)|*.*";
            //ofd.RestoreDirectory = true;
            ofd.ReadOnlyChecked = true;
            if (ofd.ShowDialog() == DialogResult.OK)
            {                
                DS_Excel = excel_Op.Import_OleDb(ofd.FileName);
                if (DS_Excel == null)
                    return;

                DataSet = new NovoDataSet(DS_Excel);
                regMap = DataSet.RegMap;
                // Init tabs with created data tables
                CreateTabs(DataSet.DS_Display);
            }
            else
                return;           
        }

        private void MenuItemFile_Open_Excel_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Title = "Please select regmap excel file...";
            ofd.Filter = "xlsx(*.xlsx)|*.xlsx|xls(*.xls)|*.xls|All Files(*.*)|*.*";
            //ofd.RestoreDirectory = true;
            ofd.ReadOnlyChecked = true;
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                DS_Excel = excel_Op.Import_OleDb(ofd.FileName);
                if (DS_Excel == null)
                    return;
                DataProcess.RemoveEmptyZone(DS_Excel);
                DataSet = new NovoDataSet(DS_Excel);
                regMap = DataSet.RegMap;
                // Init tabs with created data tables
                CreateTabs(DataSet.DS_Display);
            }
            else
                return;           

        }

        private void MenuItemFile_Open_proj_Click(object sender, EventArgs e)
        {
            OpenFileDialog openProj = new OpenFileDialog();
            openProj.Title = "open an project file and update infomations to GUI...";
            openProj.Filter = "NSPROJ(.nsproj)|*.nsproj";
            //importFile.RestoreDirectory = true;
            if (openProj.ShowDialog() == DialogResult.OK)
            {
                currentProjPath = openProj.FileName;
                DeserializeMethod(currentProjPath);

                regMap = DataSet.RegMap;
                // Init tabs with created data tables
                CreateTabs(DataSet.DS_Display);
            }
        }

        private void MenuItemFile_Save_Click(object sender, EventArgs e)
        {
            // Examine path, if no, then open save file dialog.
            if(!File.Exists(currentProjPath))            
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.Title = "save project file...";
                sfd.Filter = "NSPROJ(.nsproj)|*.nsproj";
                if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    currentProjPath = sfd.FileName;
                    historyProjPath.Add(currentProjPath);
                    if (historyProjPath.Count > maxHistProjPathCount)
                        historyProjPath.RemoveAt(0);
                }
                else
                    return;
            }
            SerializeMethod(currentProjPath);
        }

        private void MenuItemFile_Save_As_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Title = "save project file...";
            sfd.Filter = "NSPROJ(.nsproj)|*.nsproj";
            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                currentProjPath = sfd.FileName;
                historyProjPath.Add(currentProjPath);
                if (historyProjPath.Count > maxHistProjPathCount)
                    historyProjPath.RemoveAt(0);

                SerializeMethod(currentProjPath);
            }
        }

        private void MenuItemFile_Close_Click(object sender, EventArgs e)
        {
            this.tabCtrlRegView.TabPages.Clear();
            this.DataSet = null;
            this.DS_Excel = null;
        }

        private void MenuItemFile_Import_Click(object sender, EventArgs e)
        {
            if (AllTables.Count == 0)
            {
                MessageBox.Show("Please open project first!!!");
                return;
            }

            StringBuilder tempValue = new StringBuilder(255);
            OpenFileDialog importFile = new OpenFileDialog();
            importFile.Title = "Import registe setting and update to GUI...";
            importFile.Filter = "MDCFG(.mdcfg)|*.mdcfg|All File(*.*)|*.*";
            //importFile.RestoreDirectory = true;
            if(importFile.ShowDialog() == DialogResult.OK)
            {
                string filename = importFile.FileName;
                foreach(Register reg in regMap.RegList)
                {
                    GetPrivateProfileString(reg.RegName, "Value", "00", tempValue, 256, filename);
                    reg.RegValue = byte.Parse(tempValue.ToString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
                }                
            }
            //todo update GUI 
            for (int ix = 0; ix < AllTables.Count; ix++)
            {
                AllTables[ix].UpdateAllGUI_Tab();
            }
        }

        private void MenuItemFile_Export_Click(object sender, EventArgs e)
        {
            if (AllTables.Count == 0)
            {
                MessageBox.Show("Please open project first!!!");
                return;
            }

            SaveFileDialog exportFile = new SaveFileDialog();
            exportFile.Title = "Export all the register setting to local file...";
            exportFile.Filter = "MDCFG(.mdcfg)|*.mdcfg|All File(*.*)|*.*";
            //exportFile.RestoreDirectory = true;
            if (exportFile.ShowDialog() == DialogResult.OK)
            {
                string filename = exportFile.FileName;
                foreach (Register reg in regMap.RegList)
                {
                    WritePrivateProfileString(reg.RegName, "Address", "0x" + reg.RegAddress.ToString("X2"), filename);
                    WritePrivateProfileString(reg.RegName, "Value", "0x" + reg.RegValueString, filename);
                }
            }
        }

        private void MenuItemFile_Exit_Click(object sender, EventArgs e)
        {

        }

        private void MenuItemFile_ExitWithoutSave_Click(object sender, EventArgs e)
        {

        }

        Form_SetIICDevice setIICDevice = null;
        private void selectDongleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string devName = myUsbDev.GetDevName();
            setIICDevice = new Form_SetIICDevice(myUsbDev.DevID, maxUSBDevCount, devName, myUsbDev.CurrentDevAddr,
                myUsbDev.I2C_CFG.ClockSpeedHz, myUsbDev.I2C_CFG.EnablePu);
            setIICDevice.FormClosingEvent += new Form_SetIICDevice.SetIICDevClosingEventHandler(SetIICDevClosingEvent);
            setIICDevice.ShowDialog();             
        }

        private void i2CDumpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form_RegDump frm_RegDump = new Form_RegDump(myUsbDev);
            frm_RegDump.ShowDialog();
        }
        private void eOMToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form_EOM frm_EOM = new Form_EOM(myUsbDev);
            frm_EOM.ShowDialog();
        }

        void SetIICDevClosingEvent(object sender, FormClosingEventArgs e)
        {
            if (setIICDevice.SelectedDevIndex != myUsbDev.DevID)
            {
                myUsbDev.OpenDevice(setIICDevice.SelectedDevIndex);
                RefreshDongleInfo();
            }

            if (setIICDevice.DevAdd != myUsbDev.CurrentDevAddr)
            {
                myUsbDev.CurrentDevAddr = setIICDevice.DevAdd;
            }

            if (setIICDevice.I2CMode != myUsbDev.I2C_CFG.ClockSpeedHz ||
                setIICDevice.PU_EN != myUsbDev.I2C_CFG.EnablePu)
            {
                myUsbDev.IIC_Mode_Set(setIICDevice.I2CMode, setIICDevice.PU_EN);
            }

            setIICDevice = null;
        }

        private void selectDongleToolStripMenuItem_MouseEnter(object sender, EventArgs e)
        {
            //this.selectDongleToolStripMenuItem.DropDownItems.Clear();

            //int devCnt = myUsbDev.EnumDevice();
            
            //if (devCnt == 0)
            //{
            //    // 未找到设备
            //    this.selectDongleToolStripMenuItem.DropDownItems.Add("No Device");
            //}
            //else
            //{
            //    string devName = myUsbDev.GetDevName();

            //    for (int ix = 0; ix < devCnt; ix++)
            //    {
            //        this.selectDongleToolStripMenuItem.DropDownItems.Add(String.Format("{0} - {1}", devName, ix));
            //        this.selectDongleToolStripMenuItem.DropDownItems[ix].Click += new EventHandler(DongleItem_Click);
            //    }
            //}
        }
        
        public void DongleItem_Click(object sender, EventArgs e)
        {
            for (int ix = 0; ix < this.selectDongleToolStripMenuItem.DropDownItems.Count; ix++)
            {
                if (sender != this.selectDongleToolStripMenuItem.DropDownItems[ix])
                    continue;

                myUsbDev.OpenDevice(ix);
            }

            RefreshDongleInfo();
        }
        
        private void scanDeviceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            byte[] devAddr = new byte[128];
            if (myUsbDev.IsOpen)
            {
                int cnt = myUsbDev.IIC_ScanDevAddr(devAddr);
                if (cnt > 0)
                {
                    string msg = string.Empty;
                    for (int ix = 0; ix < cnt; ix++)
                    {
                        msg += string.Format("0x{0}, ", devAddr[ix].ToString("X2"));
                    }

                    MessageBox.Show(msg, "IIC Device List");
                }
                else
                    MessageBox.Show("No IIC device", "IIC Device List");

            }
            else
            {
                MessageBox.Show("No USB2IIC dongle!");
            }
        }

        private void toolStripMenuChipType_Click(object sender, EventArgs e)
        {
            this.statusBar_ChipType.Text = (sender as ToolStripMenuItem).Text;
            this.statusBar_ChipType.BackColor = (sender == toolStrip_NLS9116) ? Color.SkyBlue : Color.LightGoldenrodYellow;
        }

        private void FlashLED_Click(object sender, EventArgs e)
        {
            FlashLED();
        }

        
    }

    #endregion Events


}



